#include "procinp.h"
#include "ozawa.h"
#include "printing.h"
#include "report.h"
#include "util.h"
#include <strsafe.h>

using namespace std;
using namespace ogdf;
using namespace utl;

const string InputProcessor::REPORT_FILE_NAME = "report.txt";
const string InputProcessor::ERROR_INPUT_PATH_NOT_EXISTS = "input path not exists";
const string InputProcessor::ERROR_READING_DIRECTORY = "error reading directory";

InputProcessor::InputProcessor(const string inputPath, const bool testMode){
	this->inputPath = removeLastSlash(inputPath);
	this->testMode = testMode;
	failedFileCount = 0;
	processedFileCount = 0;
	reportWriter = new ReportWriter(testMode);
	printer = new Printer(testMode);
}

InputProcessor::~InputProcessor(){
	delete reportWriter;
	delete printer;
}

void InputProcessor::process(){
	PathType type = testPathType(inputPath);

	if(type == NOT_EXISTS){
		throw ERROR_INPUT_PATH_NOT_EXISTS;
	}

	if(type == IS_FILE){
		string graphFileName = getFileNameByPath(inputPath);
		string directory = getDirectoryByPath(inputPath);
		changeCurrentDirToInput(directory);
		reportWriter->openReportFile(REPORT_FILE_NAME);
		processGraph(graphFileName);
	}else{
		changeCurrentDirToInput(inputPath);
		reportWriter->openReportFile(REPORT_FILE_NAME);
		traverseDirectory(REPORT_FILE_NAME);
	}

	reportWriter->closeReportFile(processedFileCount, failedFileCount);
}

void InputProcessor::processGraph(const string fileName){
	printer->fileProcessingStarted(fileName);
	processedFileCount++;
	WriteReportHandler resultHandler(this);
	OzawaAlgorithm::execute(fileName, &resultHandler, printer);
}

void InputProcessor::processAlgorithmResult(const string inputFileName, const Graph* graph, const int deletedEdgesCount, const ULONGLONG executionTime) const{
	writeGraph(graph, createGraphNameForAlgorithm(inputFileName, 
		OzawaAlgorithm::getName()));
	reportWriter->writeResultsToReport(inputFileName, executionTime, 
		deletedEdgesCount);
}

void InputProcessor::processAlgorithmError(const string inputFileName, const string errorDescription){
	failedFileCount++;
	printer->testFailed();
	reportWriter->writeFailResultsToReport(inputFileName, errorDescription);
}


void InputProcessor::writeGraph(const Graph* graph, const string fileName){
	ofstream o;
	o.open(fileName.c_str());
	graph->writeGML(o);
	o.flush();
	o.close();
}

/**
*
* Traverses input directory and process each file (excepts <exclusionName>)
*
*/
void InputProcessor::traverseDirectory(const string exclusionName){
	WIN32_FIND_DATA ffd;
	TCHAR szDir[MAX_PATH];
	HANDLE hFind = INVALID_HANDLE_VALUE;

	StringCchCopy(szDir, MAX_PATH, DIR_NAME_CURRENT.c_str());
	StringCchCat(szDir, MAX_PATH, TEXT(ALL_SUBFILES.c_str()));

	hFind = FindFirstFile(szDir, &ffd);

	if (INVALID_HANDLE_VALUE == hFind) 
	{
		throw ERROR_READING_DIRECTORY;
	} 

	// traverse all files in directory
	do
	{
		// if file is not from exclusions
		if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && 
			exclusionName.compare((string)(ffd.cFileName)) != 0)
		{
			// process file
			processGraph(ffd.cFileName);
		}
	}
	while (FindNextFile(hFind, &ffd) != 0);

	FindClose(hFind);
}


WriteReportHandler::WriteReportHandler(InputProcessor* processor){
	this->processor = processor;
}

void WriteReportHandler::errorProcessionFunction(const string inputFileName, const string errorDescription) const{
	processor->processAlgorithmError(inputFileName, errorDescription);
}

void WriteReportHandler::resultProcessionFunction(const string inputFileName, const Graph *graph, const int deletedEngesCount, const ULONGLONG executionTime) const{
	processor->processAlgorithmResult(inputFileName, graph, deletedEngesCount, executionTime);
}